package com.zj.sqlSession;

import com.zj.exception.ZJBatisException;
import com.zj.executor.Executor;
import com.zj.mapping.MappedStatement;
import com.zj.utils.Configuration;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;

public class DefaultSqlSession implements SqlSession {
    private final Configuration configuration;
    private final Executor executor;
    private final boolean autoCommit;
    private boolean dirty;

    public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
        this.configuration = configuration;
        this.executor = executor;
        this.dirty = false;
        this.autoCommit = autoCommit;
    }

    public int insert(String statement) {
        return insert(statement, null);
    }

    public int insert(String statement, Object parameter) {
        return update(statement, parameter);
    }

    public int update(String statement) {
        return update(statement, null);
    }

    public int update(String statement, Object parameter) {
        try {
            dirty = true;
            MappedStatement ms = configuration.getMappedStatement(statement);
            return executor.update(ms, wrapCollection(parameter));
        } catch (Exception e) {
            throw new ZJBatisException("Error updating database.  Cause: " + e);
        } finally {
            ;
        }
    }

    public int delete(String statement) {
        return update(statement, null);
    }

    public int delete(String statement, Object parameter) {
        return update(statement, parameter);
    }
    private Object wrapCollection(final Object object) {
        if (object instanceof List) {
            HashMap<String,Object> map = new HashMap<String,Object>();
            map.put("list", object);
            return map;
        } else if (object != null && object.getClass().isArray()) {
            HashMap<String,Object> map = new HashMap<String,Object>();
            map.put("array", object);
            return map;
        }
        return object;
    }
    public <E> E selectOne(String statement, Object parameter) {
        // Popular vote was to return null on 0 results and throw exception on too many.
       try{
           MappedStatement ms = configuration.getMappedStatement(statement);
        List<E> result = executor.<E>query(ms, wrapCollection(parameter));
        if (result.size() == 1) {
            return result.get(0);
        } else if (result.size() > 1) {
            throw new ZJBatisException("Expected one result (or null) to be returned by selectOne(), but found: " + result.size());
        } else {
            return null;
        }
       }catch (Exception e){
           throw new ZJBatisException(e);
       }
    }
    public <E> List<E> selectList(String statement, Object parameter) {
        try {
            MappedStatement ms = configuration.getMappedStatement(statement);
            List<E> result = executor.<E>query(ms, wrapCollection(parameter));
            return result;
        } catch (Exception e) {
            throw new ZJBatisException(e);
        }
    }


    @Override
    public void commit() {
    commit(false);
    }

    @Override
    public void commit(boolean force) {
        try{
            executor.commit(dirty||false);
            dirty = false;
        }catch (Exception e){
            throw  new ZJBatisException(e);
        }

    }

    @Override
    public void rollback() {
        rollback(false);
    }

    @Override
    public void rollback(boolean var1) {
        try {
            executor.rollback(dirty||false);
            dirty = false;
        } catch (Exception e) {
            throw  new ZJBatisException(e);
        }
    }

    @Override
    public void close() {
        executor.close(dirty||false);
        dirty = false;
    }

    @Override
    public Configuration getConfiguration() {
        return configuration;
    }

    @Override
    public <T> T getMapper(Class<T> var1) {
        return configuration.<T>getMapper(var1, this);
    }

    @Override
    public Connection getConnection() {
        try {
            return executor.getTransaction().getConnection();
        } catch (SQLException e) {
            throw new ZJBatisException("Error getting a new connection.  Cause: " + e, e);
        }
    }


}
